package com.xunmall.gateway.security;


import com.xunmall.account.dto.UrlDto;
import com.xunmall.account.service.RoleRemoteService;
import com.xunmall.base.dto.Result;
import org.assertj.core.util.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;

import javax.servlet.http.HttpServletRequest;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 提供某个资源对应的权限定义，即getAttributes方法返回的结果。
 * 此类在初始化时，应该取到所有资源及其对应权限的定义。
 *
 * @author fanjun
 */
public class SecurityMetadataSourceService implements FilterInvocationSecurityMetadataSource {
    private Logger log = LoggerFactory.getLogger(getClass());

    private static List<UrlDto> resourceMap = Lists.newArrayList();
    private static List<UrlDto> defaultMap = Lists.newArrayList();
    private static List<UrlDto> holdUpMap = Lists.newArrayList();

    @Autowired
    private RoleRemoteService roleRemoteService;

    public synchronized void loadMetadataSource() {
/*        try {
            Result<Map<String, List<UrlDto>>> req = roleRemoteService.getMetaSource();
            if (!req.getSuccess()) {
                log.error("getMetaSource error:" + req.getMessage());
            }
            Map<String, List<UrlDto>> map = req.getData();
            // 加载默认策略
            List<UrlDto> tmpDefaultMap = map.getOrDefault("defaults", Lists.newArrayList());
            defaultMap = tmpDefaultMap;
            // 加载API策略
            List<UrlDto> tmpResourceMap = map.getOrDefault("perms", Lists.newArrayList());
            resourceMap = tmpResourceMap;
            // 加载兜底策略
            List<UrlDto> tmpHoldUpMap = map.getOrDefault("holdUp", Lists.newArrayList());
            holdUpMap = tmpHoldUpMap;

        } catch (Exception e) {
            log.error("访问策略加载失败.", e);
        }*/

        log.info("loadMetadataSource finish.");
    }

    /**
     * 根据URL，找到相关的权限配置。
     *
     * @param
     * @return
     * @throws IllegalArgumentException
     */
    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
        if (holdUpMap.size() == 0 && defaultMap.size() == 0 && resourceMap.size() == 0) {
            loadMetadataSource();
        }

        FilterInvocation filterInvocation = (FilterInvocation) object;
        HttpServletRequest httpRequest = filterInvocation.getHttpRequest();

        // 默认访问权限
        for (UrlDto url : defaultMap) {
            RequestMatcher requestMatcher = new AntPathRequestMatcher(url.getUrl(), url.getMethod());
            if (requestMatcher.matches(httpRequest)) {
                return convertCollection(url.getPermissions());
            }
        }

        // 授权访问权限(公司/ISP)
        if (httpRequest.getRequestURI().startsWith("/v1/co/") || httpRequest.getRequestURI().startsWith("/v1/is/")) {
            if (resourceMap != null) {
                for (UrlDto url : resourceMap) {
                    RequestMatcher requestMatcher = new AntPathRequestMatcher(url.getUrl(), url.getMethod());
                    if (requestMatcher.matches(httpRequest)) {
                        return convertCollection(url.getPermissions());
                    }
                }
            }
        }

        // 兜底策略
        for (UrlDto url : holdUpMap) {
            RequestMatcher requestMatcher = new AntPathRequestMatcher(url.getUrl(), url.getMethod());
            if (requestMatcher.matches(httpRequest)) {
                // TODO 用于检验通过/v1/co/**放行的url，以便在T_API表中配置，将来需要删除
                if (httpRequest.getRequestURI().startsWith("/v1/co/")) {
                    log.debug("URL PERM - URL:{} ; Method:{}", httpRequest.getRequestURI(), httpRequest.getMethod());
                }
                return convertCollection(url.getPermissions());
            }
        }

        return Lists.newArrayList();
    }

    private Collection<ConfigAttribute> convertCollection(Set<String> list) {
        Collection<ConfigAttribute> result = list.stream().map(SecurityConfig::new).collect(Collectors.toList());
        return result;
    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return FilterInvocation.class.isAssignableFrom(clazz);
    }

    /**
     * 刷新 url-权限 缓存
     */
    public void refreshMetaSource() {
        loadMetadataSource();
    }
}
